- 
          
- 
        Couldn't load subscription status. 
- Fork 320
refactor(tab): separate execute_script concerns #258
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
…rehensive options
| Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! | 
| Last commit refactors JavaScript execution by moving  | 
| I think this is too much. We can keep something with a minimal useful API, and for advanced users, they can execute the scripts directly. For instance, something like this would be better:  @overload
 async def execute_script(self, script: str, await_promise: bool = True, return_by_value: bool = True) -> EvaluateResponse: ...
 @overload
 async def execute_script(self, script: str, element: WebElement, await_promise: bool = True, return_by_value: bool = True) -> CallFunctionOnResponse: ... | 
| 
 Oh, I completely forgot about this PR due to the delayed response, and you probably closed it because of inactivity. If that’s the case, it would’ve been better to just ping me instead of closing it. I’ve just submitted the latest commit with the requested changes, so please consider reopening this PR. Also, let me explain the situation a little better. The current code from the PR uses explicit methods.  
 
  | 
| Honestly, it’d be great to keep the other arguments, as having the flexibility to tweak these parameters could be useful in some situations. | 
| Hello @3xp0rt, thanks for the feedback. We have to keep the API consistent, otherwise it'll be a breaking change. I understand your point of view, and that makes sense. My idea would be: if the user pass an WebElement to the  For now, we can keep all the arguments, but we should preserve in just one method for clarity. Lets keep just      
    @overload    # this is the signature without passing an WebElement as argument;
    async def execute_script(
        self,
        script: str,
        *,
        object_group: Optional[str] = None,
        include_command_line_api: Optional[bool] = None,
        silent: Optional[bool] = None,
        context_id: Optional[int] = None,
        return_by_value: Optional[bool] = None,
        generate_preview: Optional[bool] = None,
        user_gesture: Optional[bool] = None,
        await_promise: Optional[bool] = None,
        throw_on_side_effect: Optional[bool] = None,
        timeout: Optional[float] = None,
        disable_breaks: Optional[bool] = None,
        repl_mode: Optional[bool] = None,
        allow_unsafe_eval_blocked_by_csp: Optional[bool] = None,
        unique_context_id: Optional[str] = None,
        serialization_options: Optional[SerializationOptions] = None,
    ) -> EvaluateResponse:
    
    @overload
    async def execute_element(    # this is the signature passing an WebElement as arg
        self,
        script: str,
        element: WebElement,
        *,
        arguments: Optional[list[CallArgument]] = None,
        silent: Optional[bool] = None,
        return_by_value: Optional[bool] = None,
        generate_preview: Optional[bool] = None,
        user_gesture: Optional[bool] = None,
        await_promise: Optional[bool] = None,
        execution_context_id: Optional[int] = None,
        object_group: Optional[str] = None,
        throw_on_side_effect: Optional[bool] = None,
        unique_context_id: Optional[str] = None,
        serialization_options: Optional[SerializationOptions] = None,
    ) -> CallFunctionOnResponse:
    async def execute_element(    # this is the actual implementation
        self,
        script: str,
        element: Optional[WebElement] = None,
        *,
        arguments: Optional[list[CallArgument]] = None,
        silent: Optional[bool] = None,
        return_by_value: Optional[bool] = None,
        generate_preview: Optional[bool] = None,
        user_gesture: Optional[bool] = None,
        await_promise: Optional[bool] = None,
        execution_context_id: Optional[int] = None,
        object_group: Optional[str] = None,
        throw_on_side_effect: Optional[bool] = None,
        unique_context_id: Optional[str] = None,
        serialization_options: Optional[SerializationOptions] = None,
    ) -> Union[EvaluateResponse, CallFunctionOnResponse]:What do you think? Just make sure to document every param properly | 
…o execute-script
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR refactors the Tab.execute_script() method to separate concerns between general script execution and element-specific execution. The refactoring deprecates passing a WebElement to Tab.execute_script(), directing users to call WebElement.execute_script() directly instead. Both methods now expose comprehensive Chrome DevTools Protocol parameters for Runtime.evaluate and Runtime.callFunctionOn, enabling support for asynchronous execution and other advanced options.
Key Changes:
- Enhanced Tab.execute_script()with full CDP Runtime.evaluate parameters (includingawait_promise,return_by_value, etc.)
- Enhanced WebElement.execute_script()with full CDP Runtime.callFunctionOn parameters
- Deprecated element parameter in Tab.execute_script()with a deprecation warning
- Removed InvalidScriptWithElementexception and related validation logic
- Added Chromium binary paths for Linux systems
Reviewed Changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description | 
|---|---|
| pydoll/browser/tab.py | Refactored execute_script to expose all CDP parameters and deprecate element parameter | 
| pydoll/elements/web_element.py | Enhanced execute_script with comprehensive CDP parameters | 
| pydoll/exceptions.py | Removed InvalidScriptWithElement exception class | 
| tests/test_browser/test_browser_tab.py | Updated tests for new API and added deprecation warning tests | 
| tests/test_web_element.py | Added comprehensive tests for WebElement.execute_script with various scenarios | 
| pydoll/browser/chromium/chrome.py | Added chromium binary paths for Linux | 
| tests/test_browser/test_browser_chrome.py | Updated test data for new Linux binary paths | 
| tests/test_browser/test_browser_base.py | Updated test data for new Linux binary paths | 
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| 
 Hello! Your idea is great, which is why I tried to implement it in the recent commits. I also added Chromium paths for Linux to fix a workflow issue I was experiencing. Please review the changes. | 
Refactoring Pull Request
Refactoring Scope
The Tab class's
execute_scriptmethod inpydoll/browser/tab.py, related tests and documentation.Related Issue(s)
Addresses user feedback from GitHub Discussion #108 regarding async script execution capabilities
Description
Refactor the
execute_scriptmethod by separating concerns to improve the API design. The new implementation should support asynchronous execution usingawait_promise=Trueandreturn_by_value=True, provide additional options for flexible usage in code. The original method handled both general script execution and element-specific execution, which has been split into two focused methods:execute_script: Enhanced with comprehensive runtime options for general script executionexecute_element_script: New method specifically for executing scripts with element contextMotivation
Support for asynchronous code.
Before / After
Before
After
Performance Impact
Technical Debt
This refactoring addresses several technical debt issues:
API Changes
Testing Strategy
Testing Checklist
Risks and Mitigations
execute_script(script, element)signatureChecklist before requesting a review
poetry run task lintand fixed any issuespoetry run task testand all tests pass